import { IDBStore } from './store'
import { IDBDataType, IDBStoreBulkDeleteOptions } from './types'

export class IDBStoreDelete {
  idbStore: IDBStore
  constructor(idbStore: IDBStore) {
    this.idbStore = idbStore
  }

  /**
   * 根据主键删除某元素
   * @param id 主键值
   * @returns 被删除的元素
   */
  delete(id: string | number): Promise<void> {
    const db = this.idbStore.getDB()
    const storeName = this.idbStore.getStoreName()
    const transaction = db.transaction(storeName, 'readwrite')
    const store = transaction.objectStore(storeName)
    const req = store.delete(id)
    return new Promise(function (resolve, reject) {
      req.onsuccess = function (evt) {
        const target = evt.target as IDBRequest
        resolve(target.result)
      }
      req.onerror = function (evt) {
        const target = evt.target as IDBRequest
        reject(target.error)
      }
    })
  }

  /**
   * 批量删除. 删除某个索引下的一个范围内的数据
   * @param options 条件
   * @param options.keyName 索引名, 必须有索引, 哪怕索引传的是主键 id.
   * @param options.value 索引值
   * @param options.lower 索引值下限
   * @param options.upper 索引值上限
   * @param options.lowerOpen 下限是否开区间. 默认 false
   * @param options.upperOpen 上限是否开区间. 默认 false
   * @param options.enums 枚举值, 删除所有匹配的元素.
   * @param options.filter 自定义过滤器.
   * @returns 受影响的条数
   */
  bulkDelete(options: IDBStoreBulkDeleteOptions): Promise<number> {
    const { keyName, value, lower, upper, lowerOpen = false, upperOpen = false, filter } = options
    let range: IDBKeyRange
    if (typeof value !== 'undefined') {
      range = IDBKeyRange.only(value)
    } else if (typeof lower !== 'undefined' || typeof upper !== 'undefined') {
      range = IDBKeyRange.bound(lower || Number.MAX_SAFE_INTEGER, upper || Number.MAX_SAFE_INTEGER, lowerOpen, upperOpen)
    } else {
      throw new Error('delete: no key range')
    }
    const db = this.idbStore.getDB()
    const storeName = this.idbStore.getStoreName()
    const transaction = db.transaction(storeName, 'readwrite')
    const store = transaction.objectStore(storeName)

    // 有 key 则打开索引查询范围, 要是没有索引只能打开全量的
    const req = keyName ? store.index(keyName).openCursor(range) : store.openCursor()
    return new Promise(function (resolve, reject) {
      req.onsuccess = function (evt) {
        const target = evt.target as IDBRequest
        let count = 0
        try {
          const cursor = target.result
          if (cursor) {
            // 如果设置了过滤器, 还需要判断是否符合条件
            const ifMatchFilter = filter ? filter(cursor.value) : true
            // 设置了枚举值的, 那就需要判断是否符合条件
            // const ifMatchEnum = enums ? enums.includes(cursor.key) : true
            if (ifMatchFilter) {
              cursor.delete()
              count++
            }
            cursor.continue()
          } else {
            resolve(count)
          }
        } catch (err) {
          reject(err)
        }
      }
      req.onerror = function (evt) {
        const target = evt.target as IDBRequest
        reject(target.error)
      }
    })
  }

  /**
   * 清空表
   * @returns void
   */
  clear(): Promise<void> {
    const db = this.idbStore.getDB()
    const storeName = this.idbStore.getStoreName()
    const transaction = db.transaction(storeName, 'readwrite')
    const store = transaction.objectStore(storeName)

    const req = store.clear()
    return new Promise(function (resolve, reject) {
      req.onsuccess = function () {
        resolve()
      }
      req.onerror = function (evt) {
        const target = evt.target as IDBRequest
        reject(target.error)
      }
    })
  }
}
